package per.hx.bs.config.shiro;

import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import per.hx.bs.service.ShiroService;
import per.hx.bs.constant.Global;
import per.hx.bs.constant.Setting;
import per.hx.bs.entity.sys.SysUserDO;
import per.hx.bs.shiro.ShiroUser;
import per.hx.bs.util.Encodes;

import javax.annotation.PostConstruct;

/**
 * @author HuXing
 * @date 2018/3/9  17:33
 */
@Component("authRealm")
public class AuthRealm extends AuthorizingRealm {

    private Logger logger = LoggerFactory.getLogger(getClass());

    private final ShiroService shiroService;

    @Autowired
    public AuthRealm(ShiroService shiroService) {
        this.shiroService = shiroService;
    }


    /**
     * 设定密码校验的Hash算法与迭代次数
     */
    @PostConstruct
    public void initCredentialsMatcher() {
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(Setting.HASH_ALGORITHM);
        matcher.setHashIterations(Setting.HASH_INTERATIONS);
        setCredentialsMatcher(matcher);
    }

    /**
     * 认证回调函数,登录时调用.
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String loginName = ((UsernamePasswordToken) token).getUsername();
        SysUserDO sysUser = shiroService.userLogin(loginName);
        if (sysUser != null) {
            if (0 == sysUser.getStatus()) {
                throw new DisabledAccountException("账号已被禁用,请联系管理员");
            }
            byte[] salt = Encodes.decodeHex(sysUser.getPassword().substring(0, 16));
            return new SimpleAuthenticationInfo(new ShiroUser(sysUser.getUserId(), sysUser.getUsername(), sysUser.getName(), sysUser.getDeptId(), sysUser.getRoleIds(), sysUser.getPicId()),
                    sysUser.getPassword().substring(16), ByteSource.Util.bytes(salt), getName());
        } else {
            throw new UnknownAccountException("账号不存在");
        }
    }

    /**
     * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        logger.info("登录授权");
        ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        // 基于Role的权限信息
        info.setRoles(shiroService.listRoles(shiroUser.getRoleIds()));
        // 基于Permission的权限信息
        info.setStringPermissions(shiroService.listPerms(shiroUser.getRoleIds()));
        return info;
    }
}
